package com.slyak.spring.jpa;

import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.provider.QueryExtractor;
import org.springframework.data.jpa.repository.query.JpaParameters;
import org.springframework.data.jpa.repository.query.JpaQueryMethod;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.query.Parameter;
import org.springframework.data.repository.query.Parameters;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class GenericJpaQueryMethod extends JpaQueryMethod {

    public GenericJpaQueryMethod(Method method, RepositoryMetadata metadata, ProjectionFactory factory, QueryExtractor extractor) {
        super(method, metadata, factory, extractor);
    }

    @Override
    protected JpaParameters createParameters(Method method) {
        JpaParameters parameters =new JpaParameters(method);
        if(!parameters.hasPageableParameter()){
            int size = parameters.getNumberOfParameters();
            for(int i=0;i<size;i++){
                Parameter parameter = parameters.getParameter(i);
                if(Pageable.class.isAssignableFrom(parameter.getType())){
                    setPageableParameterIndex(parameters, i);
                    break;
                }
            }
        }
        return  parameters;
    }

    public void setPageableParameterIndex(JpaParameters parameters,int i){
        try {
            Field field = Parameters.class.getDeclaredField("pageableIndex");
            field.setAccessible(true);
            Field modifiersField = Field.class.getDeclaredField("modifiers");
            modifiersField.setAccessible(true);
            modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
            field.set(parameters, i);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
